<template>
  <div class="mapbox-map">
    <slot name="extra-item"></slot>
    <div v-if="showSearch">
      <position-search
        class="search-area"
        :show-search-result="showSearchResult"
        @changePosition="handleChangePosition"
        @handleChangeShow="handleChangeShow"
      />
      <!-- <el-button
        class="download-btn search-download-area"
        type="primary"
        icon="el-icon-download"
        @click="showDownloadPopup"
        title="数据下载"
      >
        {{ props.downloadConfig.buttonText }}
      </el-button>
      <el-button
        class="download-btn search-download-area"
        type="primary"
        icon="el-icon-info"
        @click="handleInstruction"
        title="操作指南"
      >
        操作指南
      </el-button> -->
    </div>
    <div class="map-container" :id="mapId"></div>
    

  </div>
</template>

<script setup>
import { onBeforeUnmount, onMounted, watch, ref } from 'vue'
import mapboxgl from 'mapbox-gl'
import { setHelper, deleteHelper } from '@/utils/map/index'
import PositionSearch from '@/components/position-search/positionSearch.vue'
import emitter from '@/utils/event-bus'
import * as coordtransform from 'coordtransform'
// import MapboxLanguage from "@mapbox/mapbox-gl-language";
import mapMarker from '@/assets/marker.png'
import { Message } from 'element-ui'

let _map
let _amap

// 球体长半径
const SPHERE_RADIUS = 6378245.0
// 扁率
const FLATNESS = 0.00669342162296594323

const props = defineProps({
  mapId: {
    type: String,
    required: true,
  },
  center: {
    type: Array,
    default: () => [106.49328310804757, 29.768499553618765],
  },
  baseMapConfig: {
    type: Object,
    required: true,
  },
  zoom: {
    type: Number,
    default: 12,
  },
  showSearch: {
    type: Boolean,
    default: false,
  },
  downloadConfig: {
    type: Object,
    default: () => ({
      fileName: '模板数据.gdb.zip',
      filePath: window.templatePathUrl + '/模板数据.gdb.zip',
      buttonText: '数据下载',
    }),
  },
})

const emits = defineEmits(['after-map-loaded', 'before-map-destroyed'])
const middlePoint = JSON.parse(localStorage.getItem('user'))?.user?.middlePoint?.split(',')

const showSearchResult = ref(false)
const downloadLoading = ref(false)

let marker

const addMapMarker = () => {
  const el = document.createElement('img')
  el.src = mapMarker
  el.style.width = '24px'
  el.style.height = '30px'
  marker = new mapboxgl.Marker({
    element: el,
    anchor: 'bottom',
  })
}

const handleChangePosition = (position) => {
  if (!position) {
    if (marker) {
      marker.remove()
    }
    return
  }

  // console.log("position", position);
  const center = coordtransform.gcj02towgs84(
    position.longitude,
    position.latitude
  )
  marker.setLngLat(center).addTo(_map)
  _map?.easeTo({
    center,
    zoom: 15,
  })
}

const handleChangeShow = (show) => {
  // console.log("show", show);
  showSearchResult.value = show
}

const showDownloadPopup = () => {
  emitter.emit('SHOW_DATA_DOWNLOAD_POPUP')
}

const handleInstruction = () => {
  window.open(window.INSTRUCTION_URL, '_blank')
}

onMounted(() => {
  const mapboxKey =
    'pk.eyJ1IjoiY2hhcmxpZXppaHVhaSIsImEiOiJjam52cDBvNWswNGJtM2tucWh2Ym56dTR4In0.1KneThJzfWANnLDgJbqKPw'
  const tdtKey = 'a49a9220798216424e34b531cb3fa5b2'
  mapboxgl.accessToken = mapboxKey

  _map = new mapboxgl.Map({
    container: props.mapId,
    // style: "mapbox://styles/mapbox/streets-v12",
    style: {
      version: 8,
      glyphs: "https://demotiles.maplibre.org/font/{fontstack}/{range}.pbf", // 添加 glyphs 字段，解决 label 报错
      sources: {
        // 天地图注记服务
        'tdt-labels': {
          type: 'raster',
          tiles: [
            `https://t0.tianditu.gov.cn/cia_w/wmts?tk=${tdtKey}&service=WMTS&version=1.0.0&request=GetTile&layer=cia&style=default&format=tiles&transparent=true&TileMatrixSet=w&TileMatrix={z}&TileRow={y}&TileCol={x}`,
          ],
          tileSize: 256,
        },
      },
      layers: [
        {
          id: 'tdt-labels',
          type: 'raster',
          source: 'tdt-labels',
        },
      ],
    },
    center: middlePoint || props.center,
    zoom: props.zoom,
    antialias: true,
    maxPitch: 80,
    maxZoom: 18
  })
  addMapMarker()

  setHelper(props.mapId, _map)

  _map.once('styledata', () => {
    initBaseMap()
  })

  _map.once('sourcedata', () => {
    emits('after-map-loaded', props.mapId, _map)
  })

  _map.on('move', () => {
    linkAMap()
  })

  _map.on('zoom', () => {
    linkAMap()
  })

  // _map.on("load", () => {
  // initLanguage();
  // emits("after-map-loaded", props.mapId, _map);
  // });
})

onBeforeUnmount(() => {
  if (_map) {
    emits('before-map-destroyed', props.mapId, _map)
    deleteHelper(props.mapId)
  }
})

const initBaseMap = () => {
  setBaseMap(props.baseMapConfig)
}

/**
 * 设置底图
 *
 * @param {BaseMapConfig} config 底图配置
 */
const setBaseMap = (config) => {
  const tdtKey = 'a49a9220798216424e34b531cb3fa5b2'
  switch (config.type) {
    case 'amap':
      {
        hideTdtLabelsLayer()
        const center = _map.getCenter()
        if (!_amap) {
          // @ts-ignore
          _amap = new window.AMap.Map('amap-container', {
            viewMode: '3D',
            zoom: _map.getZoom() + 1,
            center: wgs84ToGcj02(center.lng, center.lat),
          })
        }
      }
      break
    case 'vector':
      showTdtLabelsLayer()
      _map.addSource('tdt-vector', {
        type: 'raster',
        tiles: [
          `https://t0.tianditu.gov.cn/vec_w/wmts?tk=${tdtKey}&service=WMTS&version=1.0.0&request=GetTile&layer=vec&style=default&format=tiles&TileMatrixSet=w&TileMatrix={z}&TileRow={y}&TileCol={x}`,
        ],
        tileSize: 256,
      })
      _map.addLayer(
        {
          id: 'tdt-vector',
          type: 'raster',
          source: 'tdt-vector',
        },
        'tdt-labels'
      )
      break
    case 'imagery':
      showTdtLabelsLayer()
      _map.addSource('tdt-imagery', {
        type: 'raster',
        tiles: [
          `https://t0.tianditu.gov.cn/img_w/wmts?tk=${tdtKey}&service=WMTS&version=1.0.0&request=GetTile&layer=img&style=default&format=tiles&TileMatrixSet=w&TileMatrix={z}&TileRow={y}&TileCol={x}`,
        ],
        tileSize: 256,
      })
      _map.addLayer(
        {
          id: 'tdt-imagery',
          type: 'raster',
          source: 'tdt-imagery',
        },
        'tdt-labels'
      )
      break
    case 'wms':
      showTdtLabelsLayer()
      _map.addSource(config.id, {
        type: 'raster',
        tiles: [config.url],
        tileSize: 256,
      })
      _map.addLayer(
        {
          id: config.id,
          type: 'raster',
          source: config.id,
        },
        'tdt-labels'
      )
      break
    case 'wmts':
      showTdtLabelsLayer()
      _map.addSource(config.id, {
        type: 'raster',
        tiles: [config.url],
        tileSize: 256,
      })
      _map.addLayer(
        {
          id: config.id,
          type: 'raster',
          source: config.id,
        },
        'tdt-labels'
      )
      break
    default:
      break
  }
}

const showTdtLabelsLayer = () => {
  _map.setLayoutProperty('tdt-labels', 'visibility', 'visible')
}

const hideTdtLabelsLayer = () => {
  _map.setLayoutProperty('tdt-labels', 'visibility', 'none')
}

const transformLat = (inputLng, inputLat) => {
  const lat = +inputLat
  const lng = +inputLng
  let ret =
    -100.0 +
    2.0 * lng +
    3.0 * lat +
    0.2 * lat * lat +
    0.1 * lng * lat +
    0.2 * Math.sqrt(Math.abs(lng))
  ret +=
    ((20.0 * Math.sin(6.0 * lng * Math.PI) +
      20.0 * Math.sin(2.0 * lng * Math.PI)) *
      2.0) /
    3.0
  ret +=
    ((20.0 * Math.sin(lat * Math.PI) + 40.0 * Math.sin((lat / 3.0) * Math.PI)) *
      2.0) /
    3.0
  ret +=
    ((160.0 * Math.sin((lat / 12.0) * Math.PI) +
      320 * Math.sin((lat * Math.PI) / 30.0)) *
      2.0) /
    3.0
  return ret
}

const transformLng = (inputLng, inputLat) => {
  const lat = +inputLat
  const lng = +inputLng
  let ret =
    300.0 +
    lng +
    2.0 * lat +
    0.1 * lng * lng +
    0.1 * lng * lat +
    0.1 * Math.sqrt(Math.abs(lng))
  ret +=
    ((20.0 * Math.sin(6.0 * lng * Math.PI) +
      20.0 * Math.sin(2.0 * lng * Math.PI)) *
      2.0) /
    3.0
  ret +=
    ((20.0 * Math.sin(lng * Math.PI) + 40.0 * Math.sin((lng / 3.0) * Math.PI)) *
      2.0) /
    3.0
  ret +=
    ((150.0 * Math.sin((lng / 12.0) * Math.PI) +
      300.0 * Math.sin((lng / 30.0) * Math.PI)) *
      2.0) /
    3.0
  return ret
}

/**
 * 判断是否在国内，不在国内则不做偏移
 */
const outOfChina = (inputLng, inputLat) => {
  const lat = +inputLat
  const lng = +inputLng
  // 纬度 3.86~53.55, 经度 73.66~135.05
  return !(lng > 73.66 && lng < 135.05 && lat > 3.86 && lat < 53.55)
}

/**
 * wgs84 转 gcj02
 * 离线转换
 * @param inputLng
 * @param inputLat
 * @returns {number[]}
 */
const wgs84ToGcj02 = (inputLng, inputLat) => {
  const lat = +inputLat
  const lng = +inputLng
  if (outOfChina(lng, lat)) {
    return [lng, lat]
  } else {
    let dLat = transformLat(lng - 105.0, lat - 35.0)
    let dLng = transformLng(lng - 105.0, lat - 35.0)
    const radLat = (lat / 180.0) * Math.PI
    let magic = Math.sin(radLat)
    magic = 1 - FLATNESS * magic * magic
    const sqrtMagic = Math.sqrt(magic)
    dLat =
      (dLat * 180.0) /
      (((SPHERE_RADIUS * (1 - FLATNESS)) / (magic * sqrtMagic)) * Math.PI)
    dLng =
      (dLng * 180.0) /
      ((SPHERE_RADIUS / sqrtMagic) * Math.cos(radLat) * Math.PI)
    const mgLat = lat + dLat
    const mgLng = lng + dLng
    return [mgLng, mgLat]
  }
}

const linkAMap = () => {
  if (_amap) {
    const mapboxZoom = _map.getZoom() + 1
    const mapboxCenter = _map.getCenter()
    _amap.setZoom(mapboxZoom, true)
    _amap.setCenter(wgs84ToGcj02(mapboxCenter.lng, mapboxCenter.lat), true)
    _amap.setPitch(_map.getPitch(), true)
    _amap.setRotation(-_map.getBearing(), true)
  }
}

/**
 * 移除底图
 *
 * @param {BaseMapConfig} config 底图配置
 */
const removeBaseMap = (config) => {
  switch (config.type) {
    case 'amap':
      hideAMap()
      break
    case 'vector':
      if (_map.getLayer('tdt-vector')) {
        _map.removeLayer('tdt-vector')
      }
      if (_map.getSource('tdt-vector')) {
        _map.removeSource('tdt-vector')
      }
      break
    case 'imagery':
      if (_map.getLayer('tdt-imagery')) {
        _map.removeLayer('tdt-imagery')
      }
      if (_map.getSource('tdt-imagery')) {
        _map.removeSource('tdt-imagery')
      }
      break
    case 'wms':
      if (_map.getLayer(config.id)) {
        _map.removeLayer(config.id)
      }
      if (_map.getSource(config.id)) {
        _map.removeSource(config.id)
      }
      break
    case 'wmts':
      if (_map.getLayer(config.id)) {
        _map.removeLayer(config.id)
      }
      if (_map.getSource(config.id)) {
        _map.removeSource(config.id)
      }
      break
    default:
      break
  }
}

const hideAMap = () => {
  _amap?.destroy()
  _amap = null
}

watch(
  () => ({ ...props.baseMapConfig }),
  function (newValue, oldValue) {
    if (_map) {
      removeBaseMap(oldValue)

      setBaseMap(newValue)
    }
  },
  {
    deep: true,
  }
)
</script>

<style lang="scss" scoped>
.mapbox-map {
  .search-download-area {
    position: relative;
    margin-left: 20px;
    left: 460px;
    top: 20px;
    z-index: 100;
    display: inline-flex;
  }

  .search-area {
    flex: 1;
    min-width: 300px;
  }

  .map-container {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    overflow: hidden;
  }
}
</style>
